home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / kgcore / kgcore.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-30  |  20.8 KB  |  813 lines

  1. /* 
  2.  * kgcore.c --
  3.  *
  4.  *    Program that reads the image of a Sprite kernel from a
  5.  *    Sprite machine using the debugger interface.
  6.  *
  7.  * Copyright 1988 Regents of the University of California
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /sprite/src/cmds/kgcore/RCS/kgcore.c,v 1.2 91/05/23 12:28:05 mendel Exp $ SPRITE (Berkeley)";
  19. #endif not lint
  20.  
  21. #include <errno.h>
  22. #include <option.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <sys/file.h>
  26. #include <kernel/dbg.h>
  27. #include <stdlib.h>
  28.  
  29. #include <signal.h>
  30. #include <sys/types.h>
  31. #include <sys/socket.h>
  32. #include <sys/time.h>
  33. #include <netinet/in.h>
  34. #include <netdb.h>
  35. #include <sgtty.h>
  36. #define NOGAP
  37.  
  38. /*
  39.  * Library imports:
  40.  */
  41.  
  42. extern void panic();
  43. /*
  44.  * Message buffers for handling the Sprite debugger interface. This routines
  45.  * were stolen from the sprite debugger Kgdb and Kdbx. 
  46.  */
  47. static Dbg_Msg    msg;
  48. static int    msgSize;
  49. #define    MAX_TRANSFER_SIZE    1024
  50. #define    REPLY_BUFFER_SIZE    4096
  51. static    char    replyBuffer[REPLY_BUFFER_SIZE];
  52. static    char    requestBuffer[DBG_MAX_REQUEST_SIZE];
  53. #ifdef KDBX
  54. #define FIRST_MSG 0x40000000
  55. static    int    msgNum = FIRST_MSG;
  56. #else
  57. static    int    msgNum = 0;
  58. #endif
  59.  
  60. static void    RecvReply();
  61.  
  62. static    struct sockaddr_in    remote;
  63. int                kdbxTimeout = 1;
  64. static    int            netSocket;
  65.  
  66. char    *outputFileName = "vmcore";
  67. int    debug = 0;
  68. int    pageSize;
  69. int    dontDumpCode = 0;
  70. int    dumpFileCache = 0;
  71. char    *device = NULL;
  72.  
  73. Option optionArray[] = {
  74.     {OPT_DOC, NULL, NULL, "kgcore [options] hostname"},
  75.     {OPT_DOC, NULL, NULL, "kgcore [options] -d device"},
  76.     {OPT_STRING, "o", (char *) &outputFileName,
  77.     "Output file for core dump"},
  78.     {OPT_TRUE, "v", (char *) &debug,
  79.     "Print out progress info."},
  80.     {OPT_TRUE, "nt", (char *) &dontDumpCode,
  81.     "Don't include the kernel text segment in dump."},
  82.     {OPT_TRUE, "c", (char *) &dumpFileCache,
  83.     "Include the file system block cache in dump."},
  84.     {OPT_STRING, "d", (char *) &device,
  85.     "Device to read core from (instead of remote host)."},
  86. };
  87. #ifndef sprite
  88. extern char *sys_errlist[];
  89. #endif /* sprite */
  90.  
  91. /*
  92.  *----------------------------------------------------------------------
  93.  *
  94.  * CreateSocket --
  95.  *
  96.  *    Creates a UDP socket connected to the Sprite host's kernel 
  97.  *    debugger port.
  98.  *
  99.  * Results:
  100.  *    The stream ID of the socket.
  101.  *
  102.  * Side effects:
  103.  *    None.
  104.  *
  105.  *----------------------------------------------------------------------
  106.  */
  107. int
  108. CreateSocket(spriteHostName)
  109.     char    *spriteHostName;
  110. {
  111.     int            socketID;
  112.     struct hostent     *hostPtr;
  113.  
  114.     hostPtr = gethostbyname(spriteHostName);
  115.     if (hostPtr == (struct hostent *) NULL) {
  116.     (void) fprintf(stderr, "CreateSocket: unknown host \"%s\"\n",
  117.         spriteHostName);
  118.     exit(1);
  119.     }
  120.     if (hostPtr->h_addrtype != AF_INET) {
  121.     (void) fprintf(stderr, "CreateSocket: bad address type for host %s\n", 
  122.         spriteHostName);
  123.     exit(2);
  124.     }
  125.  
  126.     socketID = socket(AF_INET, SOCK_DGRAM, 0);
  127.     if (socketID < 0) {
  128.     perror("CreateSocket: socket");
  129.     exit(3);
  130.     }
  131.  
  132.     bzero((char *) &remote, sizeof(remote));
  133.     bcopy((char *) hostPtr->h_addr, (char *) &remote.sin_addr,
  134.         hostPtr->h_length);
  135.     remote.sin_port = htons(DBG_UDP_PORT);
  136.     remote.sin_family = AF_INET;
  137.  
  138.     if (connect(socketID, (struct sockaddr *) &remote, sizeof(remote)) < 0) {
  139.     perror("CreateSocket: connect");
  140.     exit(4);
  141.     }
  142.  
  143.     return(socketID);
  144. }
  145.  
  146. /*
  147.  * ----------------------------------------------------------------------------
  148.  *
  149.  *  SendRequest --
  150.  *
  151.  *     Send a request message to the kernel.
  152.  *
  153.  * Results:
  154.  *     None.
  155.  *
  156.  * Side effects:
  157.  *     None.
  158.  * ----------------------------------------------------------------------------
  159.  */
  160. static void
  161. SendRequest(numBytes)
  162.     int    numBytes;
  163. {
  164.     Dbg_Opcode    opcode;
  165.  
  166.     msgSize = numBytes;
  167.     msgNum++;
  168.     *(int *)requestBuffer = msgNum;
  169. #ifdef notdef
  170.     bcopy((char *) &msg, requestBuffer + 4, 2);
  171.     bcopy(((char *) &msg)+4, requestBuffer + 6, numBytes-2);
  172. #endif
  173.     bcopy((char *)&msg, requestBuffer + 4, numBytes);
  174.     if (write(netSocket, requestBuffer, numBytes + 4) < numBytes + 4) {
  175.     panic("SendRequest: Couldn't write to the kernel socket\n");
  176.     return;
  177.     }
  178.     opcode = (Dbg_Opcode) msg.opcode;
  179.     if (opcode == DBG_DETACH) {
  180.     int    dummy;
  181.     /*
  182.      * Wait for explicit acknowledgments of these packets.
  183.      */
  184.     RecvReply(opcode, 4, (char *) &dummy, (int *) NULL, 1);
  185.     }
  186. }
  187.  
  188. /*
  189.  * ----------------------------------------------------------------------------
  190.  *
  191.  *  RecvReply --
  192.  *
  193.  *     Receive a reply from the kernel.
  194.  *
  195.  * Results:
  196.  *     None.
  197.  *
  198.  * Side effects:
  199.  *     None.
  200.  * ----------------------------------------------------------------------------
  201.  */
  202.  
  203.     /* ARGSUSED */
  204. static void
  205. RecvReply(opcode, numBytes, destAddr, readStatusPtr, timeout)
  206.     Dbg_Opcode    opcode;
  207.     int        numBytes;
  208.     char    *destAddr;
  209.     int        *readStatusPtr;
  210.     int        timeout;
  211. {
  212.     int        status;
  213.     int        readMask;
  214.     struct    timeval    interval;
  215.     int        bytesRead;
  216.  
  217.  
  218.     if (numBytes + 8 > REPLY_BUFFER_SIZE) {
  219.     panic("numBytes <%d> > REPLY_BUFFER_SIZE <%d>\n",
  220.             numBytes + 8, REPLY_BUFFER_SIZE);
  221.     }
  222.     interval.tv_sec = kdbxTimeout;
  223.     interval.tv_usec = 0;
  224.     do {
  225.     if (timeout) {
  226.         int    numTimeouts;
  227.  
  228.         numTimeouts = 0;
  229.         /*
  230.          * Loop timing out and sending packets until a new packet
  231.          * has arrived.
  232.          */
  233.         do {
  234.         readMask = 1 << netSocket;
  235.         status = select(32, &readMask, (int *) NULL,
  236.             (int *) NULL, &interval);
  237.         if (status == 1) {
  238.             break;
  239.         } else if (status == -1) {
  240.             panic("RecvReply: Couldn't select on socket.\n");
  241.         } else if (status == 0) {
  242.             SendRequest(msgSize);
  243.             numTimeouts++;
  244.             if (numTimeouts % 10 == 0) {
  245.             (void) fprintf(stderr, "Timing out and resending\n");
  246.             (void) fflush(stderr);
  247.             }
  248.         }
  249.         } while (1);
  250.     }
  251.     if (opcode == DBG_DATA_READ || opcode == DBG_INST_READ ||
  252.         opcode == DBG_GET_VERSION_STRING || opcode == DBG_GET_DUMP_BOUNDS) {
  253.         /*
  254.          * Data and instruction reads return variable size packets.
  255.          * The first two ints are message number and status.  If
  256.          * the status is OK then the data follows.
  257.          */
  258.  
  259.         bytesRead = read(netSocket, replyBuffer, numBytes+8);
  260.         if (bytesRead < 0) {
  261.         panic("RecvReply: Error reading socket.");
  262.         }
  263.         /*
  264.          * Check message number before the size because this could
  265.          * be an old packet.
  266.          */
  267.         if (*(int *)replyBuffer != msgNum) {
  268.         printf("RecvReply: Old message number = %d, expecting %d\n",
  269.             *(int *)replyBuffer, msgNum);
  270.         fflush(stdout);
  271.         continue;
  272.         }
  273.         if (bytesRead == 8) {
  274.         /*
  275.          * Only 8 bytes so the read failed and there is no data.
  276.          */
  277.         *readStatusPtr = 0;
  278.         return;
  279.         }
  280.         if (opcode == DBG_GET_VERSION_STRING) {
  281.          strncpy(destAddr, (char *)(replyBuffer + 4),numBytes);
  282.          return;
  283.         }
  284.         if (opcode == DBG_GET_DUMP_BOUNDS) {
  285.          bcopy((char *)(replyBuffer + 4), destAddr, numBytes);
  286.         *readStatusPtr = 1;
  287.          return;
  288.         }
  289.         if (bytesRead != numBytes + 8) {
  290.         printf("RecvReply: Short read (1): op=%d exp=%d read=%d",
  291.             opcode, numBytes + 4, bytesRead);
  292.         fflush(stdout);
  293.         continue;
  294.         }
  295.         *readStatusPtr = 1;
  296.         bcopy(replyBuffer + 8, destAddr, numBytes);
  297.         return;
  298.     } else {
  299.         /*
  300.          * Normal request so just read in the message which includes
  301.          * the message number.
  302.          */
  303.         bytesRead = read(netSocket, replyBuffer, numBytes + 4);
  304.         if (bytesRead < 0) {
  305.         panic("RecvReply: Error reading socket (2).");
  306.         }
  307.         /*
  308.          * Check message number before size because it could be
  309.          * an old packet.
  310.          */
  311.         if (*(int *)replyBuffer != msgNum) {
  312.         printf("RecvReply: Old message number = %d, expecting %d\n",
  313.                 *(int *)replyBuffer, msgNum);
  314.         fflush(stdout);
  315.         continue;
  316.         }
  317.         if (bytesRead != numBytes + 4) {
  318.         (void) printf("RecvReply: Short read (2): op=%d exp=%d read=%d",
  319.             opcode, numBytes + 4, bytesRead);
  320.         }
  321.         if (*(int *)replyBuffer != msgNum) {
  322.         continue;
  323.         }
  324.         bcopy(replyBuffer + 4, destAddr, numBytes);
  325.         return;
  326.     }
  327.     } while (1);
  328. }
  329.  
  330. /*
  331.  * ----------------------------------------------------------------------------
  332.  *
  333.  * SendCommand --
  334.  *
  335.  *     Write the command over to the kernel.  
  336.  *
  337.  * Results:
  338.  *     None.
  339.  *
  340.  * Side effects:
  341.  *     None.
  342.  *
  343.  * ----------------------------------------------------------------------------
  344.  */
  345. int
  346. SendCommand(opcode, srcAddr, destAddr, numBytes)
  347.     Dbg_Opcode    opcode;        /* Which command */
  348.     char    *srcAddr;    /* Where to read data from */
  349.     char    *destAddr;    /* Where to write data to */
  350.     int        numBytes;    /* The number of bytes to read or write */
  351. {
  352.     int    status;
  353.  
  354.     msg.opcode = (short) opcode;
  355.  
  356.    switch (opcode) {
  357.     case DBG_GET_STOP_INFO:
  358.         SendRequest(sizeof(msg.opcode));
  359.         RecvReply(opcode, numBytes, destAddr, &status, 1);
  360.         break;
  361.     case DBG_DETACH:
  362.         msg.data.pc = *(int *) srcAddr;
  363.         SendRequest(sizeof(msg.opcode) + sizeof(msg.data.pc));
  364.         break;
  365.     case DBG_GET_VERSION_STRING:
  366.     case DBG_GET_DUMP_BOUNDS:
  367.         SendRequest(sizeof(msg.opcode));
  368.         RecvReply(opcode, numBytes, destAddr, &status, 1);
  369.         break;
  370.     case DBG_INST_READ:
  371.         msg.data.readMem.address = (int) srcAddr;
  372.         msg.data.readMem.numBytes = numBytes;
  373.         SendRequest(sizeof(msg.opcode) + sizeof(Dbg_ReadMem));
  374.         RecvReply(opcode, numBytes, destAddr, &status, 1);
  375.         break;
  376.     case DBG_REBOOT:
  377.         if (numBytes > 0) {
  378.         (void) strcpy(msg.data.reboot.string, (char *)srcAddr);
  379.         }
  380.         msg.data.reboot.stringLength = numBytes;
  381.         SendRequest(sizeof(msg.opcode) +
  382.             sizeof(msg.data.reboot.stringLength) +
  383.             msg.data.reboot.stringLength);
  384.         break;
  385.     default:
  386.         (void) printf("Unknown opcode %d\n", opcode);
  387.     }
  388.     return status;
  389. }
  390.  
  391. /*
  392.  *----------------------------------------------------------------------
  393.  *
  394.  * SkipGap --
  395.  *
  396.  *    Update the file offset pointer of the output file to skip over
  397.  *    a gap in the virtual memory image of a kernel.
  398.  *
  399.  * Results:
  400.  *    None.
  401.  *
  402.  * Side effects:
  403.  *    File offset pointer updated.
  404.  *
  405.  *----------------------------------------------------------------------
  406.  */
  407. void
  408. SkipGap(start, end,coreFile)
  409.     unsigned int start;    /* Starting address of gap. */
  410.     unsigned int end;    /* Ending address of gap. */
  411.     FILE    *coreFile; /* Corefile desciptor. */
  412. {
  413.      int size = (end - start);
  414.  
  415.      if (size > 0) { 
  416.      if (fseek(coreFile,size,1) < 0) {
  417.          (void) fprintf(stderr,"kgcore: Can't seek output file: %s\n",
  418.             sys_errlist[errno]);
  419.          (void) fclose(coreFile);
  420.          exit(1);
  421.      }
  422.     }
  423. }
  424.  
  425. /*
  426.  *----------------------------------------------------------------------
  427.  *
  428.  * CopyMem --
  429.  *
  430.  *    Copy memory from the remote machine into a file.
  431.  *
  432.  * Results:
  433.  *    Number of bytes copied.
  434.  *
  435.  * Side effects:
  436.  *    File pointer updated.
  437.  *
  438.  *----------------------------------------------------------------------
  439.  */
  440. int
  441. CopyMem(start, size, coreFile)
  442.     unsigned int start;        /* Starting address of copy. */
  443.     unsigned int size;        /* Size of copy. */
  444.     FILE    *coreFile;    /* Output file.. */
  445. {
  446.     unsigned int address, endAddress;
  447.     char buffer[MAX_TRANSFER_SIZE];
  448.     int    good;
  449.     int len;
  450.     int    bytes = 0;
  451.  
  452.     /*
  453.      * If the starting address is not a multiple of the desired transfer size
  454.      * do a small transfer to round it up.  
  455.      */
  456.     if (start & (MAX_TRANSFER_SIZE - 1)) {
  457.     len = MAX_TRANSFER_SIZE - (start & (MAX_TRANSFER_SIZE - 1));
  458.     if (len > size) {
  459.         len = size;
  460.     }
  461.     good = SendCommand(DBG_INST_READ,(char *)start,buffer,len);
  462.     if (good) {
  463.          if (fwrite(buffer,len,1,coreFile) != 1) {
  464.          (void) fprintf(stderr,"kgcore: Can't write file outfile: %s\n"
  465.             ,sys_errlist[errno]);
  466.          (void) fclose(coreFile);
  467.          exit(1);
  468.          }
  469.          bytes += len;
  470.     } else {
  471.          SkipGap(start, start + len,coreFile);
  472.     }
  473.     start += len;
  474.     size -= len;
  475.     }
  476.     /*
  477.      * Now that start is aligned correctly, transfer as many as possible
  478.      * MAX_TRANSFER_SIZE units.
  479.      */
  480.     endAddress = start + size;
  481.     for (address = start; (address + MAX_TRANSFER_SIZE)  < endAddress; ) {
  482.     good = SendCommand(DBG_INST_READ,(char *)address,buffer,
  483.                     MAX_TRANSFER_SIZE);
  484.     if (good) {
  485.          if (fwrite(buffer,MAX_TRANSFER_SIZE,1,coreFile) != 1) {
  486.          (void) fprintf(stderr,"kgcore: Can't write file outfile: %s\n"
  487.             ,sys_errlist[errno]);
  488.          (void) fclose(coreFile);
  489.          exit(1);
  490.          }
  491.          bytes += MAX_TRANSFER_SIZE;
  492.          address += MAX_TRANSFER_SIZE;
  493.     } else {
  494.         /*
  495.          * If a read fails we can skip over the whole page. We must be
  496.          * a little careful because the start address maybe invalid
  497.          * but not on a page boundry.
  498.          */
  499.          len = pageSize - (address & (pageSize - 1));
  500.          SkipGap(address,address + len,coreFile);
  501.          address += len;
  502.     }
  503.     }
  504.     /*
  505.      * Do any partial transfer that maybe left over.
  506.      */
  507.     if (address < endAddress) {
  508.     len = endAddress - address;
  509.     good = SendCommand(DBG_INST_READ,(char *)address,buffer,len);
  510.     if (good) {
  511.          if (fwrite(buffer,len,1,coreFile) != 1) {
  512.          (void) fprintf(stderr,"kgcore: Can't write file outfile: %s\n"
  513.             ,sys_errlist[errno]);
  514.          (void) fclose(coreFile);
  515.          exit(1);
  516.          }
  517.          bytes += len;
  518.     } else {
  519.          SkipGap(address,endAddress,coreFile);
  520.     }
  521.     }
  522.     return bytes;
  523. }
  524.  
  525. /*
  526.  *----------------------------------------------------------------------
  527.  *
  528.  * CopyDev --
  529.  *
  530.  *    Copy data from the device into a file.
  531.  *
  532.  * Results:
  533.  *    Number of bytes copied.
  534.  *
  535.  * Side effects:
  536.  *    File pointer updated.
  537.  *
  538.  *----------------------------------------------------------------------
  539.  */
  540. int
  541. CopyDev(fd, size, coreFile)
  542.     int        fd;        /* Device stream. */
  543.     unsigned int size;        /* Size of copy. */
  544.     FILE    *coreFile;    /* Output file.. */
  545. {
  546.     int        sectors;
  547.     int        offset;
  548.     char    *buffer;
  549.     int        bytes;
  550.  
  551.     /*
  552.      * Round up size to be a whole number of sectors.
  553.      */
  554.     if (size & 511) {
  555.     size += 512 - (size & 511);
  556.     }
  557.     buffer = malloc(size);
  558.     bytes = read(fd, buffer, size);
  559.     if (bytes != size) {
  560.     perror("Short read of device\n");
  561.     exit(1);
  562.     }
  563.     bytes = fwrite(buffer, 1, size, coreFile);
  564.     if (bytes != size) {
  565.     perror("Short write to core file\n");
  566.     exit(1);
  567.     }
  568.     free(buffer);
  569.     return bytes;
  570. }
  571.  
  572.  
  573.  
  574.  
  575. /*
  576.  *----------------------------------------------------------------------
  577.  *
  578.  * main --
  579.  *
  580.  *    Main program for "kgcore".
  581.  *
  582.  * Results:
  583.  *    None.
  584.  *
  585.  * Side effects:
  586.  *
  587.  *----------------------------------------------------------------------
  588.  */
  589.  
  590. main(argc, argv)
  591.     int        argc;
  592.     char    **argv;
  593. {
  594.     StopInfo    stopInfo;
  595.     char    versionString[100];
  596.     Dbg_DumpBounds bounds;
  597.     FILE    *coreFile;
  598.     int        good;
  599.     int        bytes;
  600.     int        totalBytes = 0;
  601.     int        devfd;
  602.     char    sector[512];
  603.     int        n;
  604.  
  605.     pageSize = getpagesize();
  606.  
  607.     argc = Opt_Parse(argc, argv, optionArray, Opt_Number(optionArray), 0);
  608.     if (!(((argc == 1) && (device != NULL)) || 
  609.       ((argc == 2) && (device == NULL)))) { 
  610.     Opt_PrintUsage(argv[0], optionArray, Opt_Number(optionArray));
  611.     exit(1);
  612.     }
  613.     if (device == NULL) {
  614.     /*
  615.      * Connect to the remote machine, read, and print the version string.
  616.      */
  617.     netSocket = CreateSocket(argv[1]);
  618.     (void) SendCommand(DBG_GET_VERSION_STRING, (char *)0, 
  619.         versionString, 100);
  620.     printf("Dumping machine %s kernel:\n%s\n",argv[1],versionString);
  621.     good = SendCommand(DBG_GET_DUMP_BOUNDS, (char *)0, (char *)&bounds, 
  622.                             sizeof(bounds));
  623.     if (!good) {
  624.         (void) fprintf(stderr,"%s: Can't get dump bounds from %s\n",
  625.             argv[0], argv[1]);
  626.         exit(1);
  627.     }
  628.     } else {
  629.     devfd = open(device, O_RDONLY);
  630.     if (devfd < 0) {
  631.        perror("Device open failed");
  632.        exit(1);
  633.     }
  634.     n = read(devfd, sector, 512);
  635.     if (n != 512) {
  636.         perror("Short read of version string");
  637.         exit(1);
  638.     }
  639.     strcpy(versionString, sector);
  640.     printf("Dumping from %s kernel: %s\n", device, versionString);
  641.     n = read(devfd, sector, 512);
  642.     if (n != 512) {
  643.         perror("Short read of stopInfo");
  644.         exit(1);
  645.     }
  646.     bcopy(sector, &stopInfo, sizeof(stopInfo));
  647.     n = read(devfd, sector, 512);
  648.     if (n != 512) {
  649.         perror("Short read of bounds");
  650.         exit(1);
  651.     }
  652.     bcopy(sector, &bounds, sizeof(bounds));
  653.     }
  654.  
  655.     printf ("Page: %d\nUserStack: %d\nCodeStart: %d\n    Size: %d\nDataStart: %d\n    Size: %d\nStacksStart: %d\n      Size: %d\nCacheStart: %d\n     Size: %d\n", bounds.pageSize, bounds.stackSize, bounds.kernelCodeStart, bounds.kernelCodeSize, bounds.kernelDataStart, bounds.kernelDataSize, bounds.kernelStacksStart, bounds.kernelStacksSize, bounds.fileCacheStart, bounds.fileCacheSize);
  656.     fflush(stdout);
  657.     /*
  658.      * Check for and correct if data segment grew into stack segments.
  659.      * This can happen if the system panic`ed because it ran out of
  660.      * memory.
  661.      */
  662.     if (bounds.kernelDataStart + bounds.kernelDataSize > 
  663.         bounds.kernelStacksStart) {
  664.     (void) fprintf(stderr,
  665.         "%s: Warning: Data segment spills into stack segment\n", 
  666.             argv[1]);
  667.     (void) fprintf(stderr, 
  668.         "%s: Data segment truncated to 0x%x from 0x%x\n",
  669.             argv[1], bounds.kernelStacksStart,
  670.             bounds.kernelDataStart + bounds.kernelDataSize);
  671.     bounds.kernelDataSize = bounds.kernelStacksStart - 
  672.                 bounds.kernelDataStart;
  673.     }
  674.  
  675.     pageSize = bounds.pageSize;
  676.     /*
  677.      * Open the core file and write the stopInfo and bounds.
  678.      */
  679.     coreFile = fopen(outputFileName,"w");
  680.     if (coreFile == (FILE *) NULL) {
  681.      (void) fprintf(stderr,
  682.          "%s: Can't open %s: %s\n",argv[0],outputFileName,
  683.         sys_errlist[errno]);
  684.       exit(1);
  685.     }
  686.     if (device == NULL) {
  687.     (void) SendCommand(DBG_GET_STOP_INFO, (char *)NULL, (char *)&stopInfo,
  688.                 sizeof(stopInfo));
  689.     }
  690.     if ((fwrite((char *)&stopInfo,sizeof(stopInfo),1,coreFile) != 1) ||
  691.     (fwrite((char *)&bounds,sizeof(bounds),1,coreFile) != 1)) {
  692.      (void) fprintf(stderr,"%s: Can't write file %s: %s\n",argv[0],
  693.         outputFileName,sys_errlist[errno]);
  694.      (void) fclose(coreFile);
  695.      exit(1);
  696.     }
  697.     totalBytes += sizeof(stopInfo) + sizeof(bounds);
  698.  
  699.     /*
  700.      * Dump the kernel code segument.
  701.      */
  702.     if (!dontDumpCode) {
  703.     if (debug) {
  704.         printf("Dumping kernel code 0x%x - 0x%x (%d bytes)...",
  705.             bounds.kernelCodeStart, 
  706.             bounds.kernelCodeStart + bounds.kernelCodeSize,
  707.             bounds.kernelCodeSize);
  708.         fflush(stdout);
  709.     }
  710.     if (device == NULL) {
  711.         bytes = CopyMem(bounds.kernelCodeStart, bounds.kernelCodeSize,
  712.             coreFile);
  713.     } else {
  714.         bytes = CopyDev(devfd, bounds.kernelCodeSize, coreFile);
  715.     }
  716.  
  717.     totalBytes += bytes;
  718.     if (debug) {
  719.         printf(" done %d bytes\n",bytes);
  720.     }
  721. #ifndef NOGAP
  722.     SkipGap(bounds.kernelCodeStart + bounds.kernelCodeSize,
  723.          bounds.kernelDataStart, coreFile);
  724. #endif
  725.     } else {
  726.     if (debug) {
  727.         printf("Skipping text segment to 0x%x\n",bounds.kernelDataStart);
  728.     }
  729. #ifndef NOGAP
  730.     SkipGap(bounds.kernelCodeStart, bounds.kernelDataStart, coreFile);
  731. #else
  732.     SkipGap(bounds.kernelCodeStart, bounds.kernelCodeStart + bounds.kernelCodeSize);
  733. #endif
  734.     }
  735.     /*
  736.      * Follow the code by the kernel data segument.
  737.      */
  738.     if (debug) {
  739.     printf("Dumping kernel data 0x%x - 0x%x (%d bytes) ...",
  740.         bounds.kernelDataStart, 
  741.         bounds.kernelDataStart + bounds.kernelDataSize,
  742.         bounds.kernelDataSize);
  743.     fflush(stdout);
  744.     }
  745.     if (device == NULL) {
  746.     bytes = CopyMem(bounds.kernelDataStart, bounds.kernelDataSize, 
  747.         coreFile);
  748.     } else {
  749.     bytes = CopyDev(devfd, bounds.kernelDataSize, coreFile);
  750.     }
  751.     totalBytes += bytes;
  752.     if (debug) {
  753.      printf(" done %d bytes\n",bytes);
  754.     }
  755. #ifndef NOGAP
  756.     SkipGap(bounds.kernelDataStart + bounds.kernelDataSize, 
  757.         bounds.kernelStacksStart, coreFile);
  758. #endif
  759.     /*
  760.      * Follow the data by the kernel stacks.
  761.      */
  762.     if (debug) {
  763.     printf("Dumping kernel stacks 0x%x - 0x%x (%d bytes) ...",
  764.         bounds.kernelStacksStart, 
  765.         bounds.kernelStacksStart + bounds.kernelStacksSize,
  766.         bounds.kernelStacksSize);
  767.     fflush(stdout);
  768.     }
  769.     if (device == NULL) {
  770.     bytes = CopyMem(bounds.kernelStacksStart, bounds.kernelStacksSize,
  771.         coreFile);
  772.     } else {
  773.     bytes = CopyDev(devfd, bounds.kernelStacksSize, coreFile);
  774.     }
  775.     totalBytes += bytes;
  776.     if (debug) {
  777.      printf(" done %d bytes\n",bytes);
  778.     }
  779.     /*
  780.      * And optionally the file system block cache.
  781.      */
  782.     if (dumpFileCache) {
  783. #ifndef NOGAP
  784.     SkipGap(bounds.kernelStacksStart + bounds.kernelStacksSize, 
  785.         bounds.fileCacheStart, coreFile);
  786. #endif
  787.     if (debug) {
  788.         printf("Dumping file cache 0x%x - 0x%x (%d bytes) ...",
  789.             bounds.fileCacheStart, 
  790.             bounds.fileCacheStart + bounds.fileCacheSize,
  791.             bounds.fileCacheSize);
  792.         fflush(stdout);
  793.     }
  794.     bytes = CopyMem(bounds.fileCacheStart, bounds.fileCacheSize, coreFile);
  795.     totalBytes += bytes;
  796.     if (debug) {
  797.          printf(" done %d bytes\n",bytes);
  798.     }
  799.     }
  800.     if (fclose(coreFile) == EOF) {
  801.      (void) fprintf(stderr,"%s: Error closing file %s: %s\n",argv[0],
  802.         outputFileName,sys_errlist[errno]);
  803.     }
  804.     if (device == NULL) {
  805.     printf("%s: Dumped %d bytes from %s into %s.\n",argv[0], totalBytes,
  806.                 argv[1], outputFileName);
  807.     } else {
  808.     printf("%s: Dumped %d bytes from %s into %s.\n",argv[0], totalBytes,
  809.                 device, outputFileName);
  810.     }
  811.     exit(0);
  812. }
  813.